package com.snails.net.restful.rx;

import android.text.TextUtils;

import com.snails.net.restful.common.HttpMethod;
import com.snails.net.restful.common.RestCreator;

import java.io.File;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import io.reactivex.Observable;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;

public final class RxRestClient {
    private final Builder builder;

    private RxRestClient(Builder builder) {
        this.builder = builder;
    }

    private Observable<String> request(HttpMethod method) {
        final RxRestService service = RestCreator.getRxRestService();
        Observable<String> observable = null;

        switch (method) {
            case GET: {
                observable = service.get(builder.url, builder.params, builder.headers);
            }
            break;

            case POST: {
                observable = service.post(builder.url, builder.params, builder.headers);
            }
            break;

            case POST_RAW: {
                observable = service.postRaw(builder.url, builder.body, builder.headers);
            }
            break;

            case PUT: {
                observable = service.put(builder.url, builder.params, builder.headers);
            }
            break;

            case PUT_RAW: {
                observable = service.putRaw(builder.url, builder.body, builder.headers);
            }
            break;

            case DELETE: {
                observable = service.delete(builder.url, builder.params, builder.headers);
            }
            break;

            case UPLOAD: {
                final MediaType mediaType = MediaType.parse(MultipartBody.FORM.toString());
                RequestBody requestBody = RequestBody.create(mediaType, builder.file);
                MultipartBody.Part body = MultipartBody.Part
                        .createFormData("file", builder.file.getName(), requestBody);
                observable = service.upload(builder.url, body, builder.headers);
            }
            break;

            default:
                break;
        }

        return observable;
    }

    public final Observable<String> get() {
        return request(HttpMethod.GET);
    }

    public final Observable<String> post() {
        if (builder.body == null) {
            return request(HttpMethod.POST);
        } else {
            if (!builder.params.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            return request(HttpMethod.POST_RAW);
        }
    }

    public final Observable<String> put() {
        if (builder.body == null) {
            return request(HttpMethod.PUT);
        } else {
            if (!builder.params.isEmpty()) {
                throw new RuntimeException("params must be null!");
            }
            return request(HttpMethod.PUT_RAW);
        }
    }

    public final Observable<String> delete() {
        return request(HttpMethod.DELETE);
    }

    public final Observable<String> upload() {
        return request(HttpMethod.UPLOAD);
    }

    public final Observable<ResponseBody> download() {
        return RestCreator.getRxRestService().download(builder.url, builder.params, builder.headers);
    }

    // ================================================================================
    // --- ---
    // ================================================================================
    public static class Builder {
        private String url = "";
        private LinkedHashMap<String, Object> params = new LinkedHashMap<>();
        private Map<String, String> headers = new HashMap<>();
        private File file = null;
        private RequestBody body = null;

        public final Builder url(String url) {
            this.url = url;
            return this;
        }

        public final Builder params(Map<String, Object> params) {
            if (params != null && params.size() > 0) {
                this.params.putAll(params);
            }
            return this;
        }

        public final Builder params(String key, Object value) {
            if (!TextUtils.isEmpty(key)) {
                this.params.put(key, value);
            }
            return this;
        }

        public final Builder headers(Map<String, String> headers) {
            if (headers != null && headers.size() > 0) {
                this.headers.putAll(headers);
            }
            return this;
        }

        public final Builder headers(String key, String value) {
            if (!TextUtils.isEmpty(key)) {
                this.headers.put(key, value);
            }
            return this;
        }

        public final Builder headers(String key, Object value) {
            if (!TextUtils.isEmpty(key)) {
                this.headers.put(key, value == null ? "" : String.valueOf(value));
            }
            return this;
        }

        public final Builder file(File file) {
            this.file = file;
            return this;
        }

        public final Builder file(String file) {
            if (!TextUtils.isEmpty(file)) {
                this.file = new File(file);
            }
            return this;
        }

        public final Builder raw(String raw) {
            this.body = RequestBody.create(MediaType.parse("application/json;charset=UTF-8"), raw);
            return this;
        }

        public final RxRestClient build() {
            return new RxRestClient(this);
        }
    }
}
